class_name NodeStateMachine
extends Node


@export var enabled: bool = true
@export var initial_node_state: NodeState
@export var root: Node2D

var node_states : Dictionary[StringName,NodeState] = {}
var current_node_state : NodeState
var current_node_state_name : String
var parent_node_name: String

# 生成时的初始状态，若此变量不为空，则使用此设置忽略 initial_node_state 的设置
var spawn_initial_node_state: String


func _ready() -> void:
	parent_node_name = get_parent().get_name()

	for child in get_children():
		if child is NodeState:
			node_states[child.name.to_lower()] = child
			child.state_matchine = self
			child.transition.connect(transition_to)

	# 此处等待一帧后再转换到初始状态，防止初始状态中使用 _ready 时 @expret 变量未完成初始化
	await get_tree().process_frame
	_initial_node_state()


func _process(delta : float) -> void:
	if not enabled:
		return
	if current_node_state and not current_node_state._changing_state:
		current_node_state._on_process(delta)


func _physics_process(delta: float) -> void:
	if not enabled:
		return
	if current_node_state and not current_node_state._changing_state:
		current_node_state._on_physics_process(delta)


func _initial_node_state():
	if spawn_initial_node_state:
		transition_to(spawn_initial_node_state)
	elif initial_node_state:
		transition_to(initial_node_state.name)


func transition_to(node_state_name : String, data: NodeStateData = null) -> void:
	node_state_name = node_state_name.to_lower()

	var new_node_state := node_states.get(node_state_name) as NodeState
	if !new_node_state:
		return

	if node_state_name == current_node_state_name and not new_node_state._allow_repeat_enter():
		return

	if current_node_state:
		current_node_state._on_exit()
		current_node_state._changing_state = false

	var new_node_state_name := new_node_state.name.to_lower()
	if data:
		data.old_state_name = current_node_state_name
		data.new_state_name = new_node_state_name
	new_node_state._on_enter(data)

	current_node_state = new_node_state
	current_node_state_name = new_node_state_name

	print("Current State: ", get_parent().name, ".", current_node_state_name)
